﻿namespace Pattern_package.GUI
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using Pattern_package.Create_Correct_Pattern;

    /// <summary>
    /// classify form
    /// </summary>
    public partial class Classify_Form : Form
    {
        /// <summary>
        /// information for data in each class
        /// </summary>
        Sample_info.InfoOfClass[] classInfo;

        /// <summary>
        /// index of class I insert input in it
        /// </summary>
        int ClassIndexNow = 0;

        /// <summary>
        /// result image
        /// </summary>
        private Bitmap result;

        /// <summary>
        /// type of input image created or input
        /// </summary>
        private string typeOfImage;

        /// <summary>
        /// values of feature color in each pixel
        /// </summary>
        private double[,] ValuesOfFeatures;

        /// <summary>
        /// number of classies in classify
        /// </summary>
        private int NumberOfClass;

        /// <summary>
        /// type of classify found
        /// </summary>
        private enum TypeOfClassify
        {
            knownParamater,
            Likelihood,parzenWindow,KNearestNeighbour,k_mean
        }

        /// <summary>
        /// type of classify use
        /// </summary>
        private TypeOfClassify MyType;

        /// <summary>
        /// color for each class
        /// </summary>
        private List<Color> colorOfEachClass;

        /// <summary>
        /// the centers in case of k-means
        /// </summary>
        private double[] centers;
        /// <summary>
        /// number of correct classify
        /// </summary>
        private int NumberOfCorrectClassify;

        /// <summary>
        /// number of pixel unclassify
        /// </summary>
        private int NumberOfUnClassify;

        /// <summary>
        /// Initializes a new instance of the <see cref="Classify_Form"/> class.
        /// </summary>
        public Classify_Form()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Gets or sets the type of image.
        /// </summary>
        /// <value>
        /// The type of image.
        /// </value>
        public string TypeOfImage
        {
            get { return this.typeOfImage; }
            set { this.typeOfImage = value; }
        }

        /// <summary>
        /// Gets or sets the values of features1.
        /// </summary>
        /// <value>
        /// The values of features1.
        /// </value>
        public double[,] ValuesOfFeatures1
        {
            get { return this.ValuesOfFeatures; }
            set { this.ValuesOfFeatures = value; }
        }

        /// <summary>
        /// Gets or sets the number of class1.
        /// </summary>
        /// <value>
        /// The number of class1.
        /// </value>
        public int NumberOfClass1
        {
            get { return this.NumberOfClass; }
            set { this.NumberOfClass = value; }
        }

        /// <summary>
        /// Sets the values from class call me.
        /// </summary>
        /// <param name="ValuesOfFeatures">The values of features.</param>
        /// <param name="typeOfImage">The type of image.</param>
        /// <param name="NumberOfClass">The number of class.</param>
        /// <param name="image">The image input.</param>
        public void SetValues(double[,] ValuesOfFeatures, string typeOfImage, int NumberOfClass, Bitmap image)
        {
            this.classInfo = new Sample_info.InfoOfClass[NumberOfClass];
            this.ValuesOfFeatures1 = ValuesOfFeatures;
            this.NumberOfClass1 = NumberOfClass;
            this.TypeOfImage = typeOfImage;
           this.NumberOfCorrectClassify = 0;
            this.NumberOfUnClassify = 0;
            this.picOriginalImage.Image = image;
           this.result = new Bitmap(this.ValuesOfFeatures.GetLength(0), this.ValuesOfFeatures.GetLength(1));
            Random Rand = new Random();
            this.colorOfEachClass = new List<Color>();
            for (int i = 0; i < this.NumberOfClass; i++)
            {
                this.classInfo[i].data = new List<double>();
                this.classInfo[i].prob = 1 / (float)this.NumberOfClass;
                Color newColor = this.ChooseColorOfClass(Rand);
                this.colorOfEachClass.Add(newColor);
            }
        }

        /// <summary>
        /// Chooses the color of class random.
        /// </summary>
        /// <param name="Rand">The rand use in choose.</param>
        /// <returns></returns>
        private Color ChooseColorOfClass(Random Rand)
        {
            bool diff;
            Color newColor;
            do
            {
                diff = true;
                double FractOfRed = Rand.NextDouble();
                double FractOfGreen = Rand.NextDouble();
                double FractOfBlue = Rand.NextDouble();
                newColor = Color.FromArgb((int)(FractOfRed * 255), (int)(FractOfGreen * 255), (int)(FractOfBlue * 255));
                if (newColor == Color.Black)
                    diff = false;
                if (this.colorOfEachClass.Count != 0)
                {
                    for (int j = 0; j < this.colorOfEachClass.Count; j++)
                    {
                        if (newColor == this.colorOfEachClass[j])
                        {
                            diff = false;
                            break;
                        }
                    }
                }
            } while (diff == false);

            return newColor;
        }

        /// <summary>
        /// Handles the Click event of the knownVariablesToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void knownVariablesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClassIndexNow = 0;
            KnownParamterData.Rows.Clear();
            KnownParamterData.Rows.Add(this.NumberOfClass);
            for (int i = 0; i < this.NumberOfClass; i++)
            {
                KnownParamterData.Rows[i].Cells[0].Value = i;
            }
            this.KnownParamterData.Visible = true;
            this.MyType = TypeOfClassify.knownParamater;
            this.GBResult.Visible = true;
        }

        /// <summary>
        /// Handles the Click event of the BtnClassify control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnClassify_Click(object sender, EventArgs e)
        {
            this.NumberOfCorrectClassify = 0;
            this.NumberOfUnClassify = 0;
            switch (this.MyType)
            {
                case TypeOfClassify.knownParamater:
                    {
                        Create_Correct_Pattern.NormalDistrubution[] KnowNormalDis = new Create_Correct_Pattern.NormalDistrubution[this.NumberOfClass];
                        this.LoadNormalDistDataForeachClassForKnownVariable(ref KnowNormalDis);
                        this.Classified(KnowNormalDis);
                        this.picResultImage.Image = this.result;
                        this.txtPerClassifyCorrect.Text = (((double)this.NumberOfCorrectClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerUnClassify.Text = (((double)this.NumberOfUnClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerClassifyError.Text = (100 - double.Parse(this.txtPerClassifyCorrect.Text) - double.Parse(this.txtPerUnClassify.Text)).ToString();
                    }
                    break;
                case TypeOfClassify.Likelihood:
                    {
                        NormalDistrubution[] normalInfo = new NormalDistrubution[this.classInfo.Length];
                        EstimateValue newEsti = new EstimateValue();
                        newEsti.EstimateValueInNormal(ref normalInfo, this.classInfo);
                        this.Classified(normalInfo);
                        this.picResultImage.Image = this.result;
                        this.txtPerClassifyCorrect.Text = (((double)this.NumberOfCorrectClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerUnClassify.Text = (((double)this.NumberOfUnClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerClassifyError.Text = (100 - double.Parse(this.txtPerClassifyCorrect.Text) - double.Parse(this.txtPerUnClassify.Text)).ToString();
                    }
                    break;
                case TypeOfClassify.parzenWindow:
                    {
                        Classify_data.PazernWindow pazernClassify = new Classify_data.PazernWindow();
                        pazernClassify.setInfo(this.classInfo, this.NumberOfClass, this.colorOfEachClass, int.Parse(this.TxtbWindowSize.Text), this.ValuesOfFeatures);
                        this.picResultImage.Image =pazernClassify.Classfiy();
                        this.txtPerClassifyCorrect.Text = (((double)pazernClassify.NumberOfCorrectClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerUnClassify.Text = (((double)pazernClassify.NumberOfUnClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerClassifyError.Text = (100 - double.Parse(this.txtPerClassifyCorrect.Text) - double.Parse(this.txtPerUnClassify.Text)).ToString();
                    
                    }
                    break;
                case TypeOfClassify.KNearestNeighbour:
                    {
                        Classify_data.KNearestNeighbour knearneghbour = new Classify_data.KNearestNeighbour();
                        knearneghbour.setInfo(this.classInfo, this.NumberOfClass, this.colorOfEachClass, int.Parse(this.TxtbK.Text), this.ValuesOfFeatures);
                        this.picResultImage.Image = knearneghbour.Classify();
                        this.txtPerClassifyCorrect.Text = (((double)knearneghbour.NumberOfCorrectClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerUnClassify.Text = (((double)knearneghbour.NumberOfUnClassify / this.ValuesOfFeatures.Length) * 100.0).ToString();
                        this.txtPerClassifyError.Text = (100 - double.Parse(this.txtPerClassifyCorrect.Text) - double.Parse(this.txtPerUnClassify.Text)).ToString();
                    
                    }
                    break;
                case TypeOfClassify.k_mean:
                    {
                        Classify_data.K_mean kmean = new Classify_data.K_mean();
                        kmean.SetInfo(this.colorOfEachClass,this.ValuesOfFeatures,  this.NumberOfClass,this.centers );
                        this.picResultImage.Image = kmean.Classify();
                    }
                    break;
                    
            }
        }

        /// <summary>
        /// Classifieds the input with specified know normal dis.
        /// </summary>
        /// <param name="KnowNormalDis">The know normal dis.</param>
        private void Classified(NormalDistrubution[] KnowNormalDis)
        {
            Pattern_package.Classify_data.Baysian myBaysian = new Classify_data.Baysian();
            for (int i = 0; i < this.ValuesOfFeatures.GetLength(0); i++)
            {
                for (int j = 0; j < this.ValuesOfFeatures.GetLength(1); j++)
                {
                    int index = myBaysian.ChooseType(KnowNormalDis, this.ValuesOfFeatures[i, j]);
                    if (index == -1)
                    {
                        this.result.SetPixel(i, j, Color.Black);
                        this.NumberOfUnClassify++;
                    }
                    else
                    {
                        this.result.SetPixel(i, j, this.colorOfEachClass[index]);
                        if (i >= (index * this.ValuesOfFeatures.GetLength(0) / this.NumberOfClass) && i < ((index * this.ValuesOfFeatures.GetLength(0) / this.NumberOfClass) + (this.ValuesOfFeatures.GetLength(0) / this.NumberOfClass)))
                        {
                            this.NumberOfCorrectClassify++;
                        }
                        else
                        {
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Loads the normal dist data foreach class for known variable.
        /// </summary>
        /// <param name="KnowNormalDis">The know normal dis.</param>
        private void LoadNormalDistDataForeachClassForKnownVariable(ref NormalDistrubution[] KnowNormalDis)
        {
            for (int i = 0; i < this.NumberOfClass; i++)
            {
                KnowNormalDis[i].mean = double.Parse(KnownParamterData.Rows[i].Cells[1].Value.ToString());
                KnowNormalDis[i].sigma = double.Parse(KnownParamterData.Rows[i].Cells[2].Value.ToString());
            }
        }

        /// <summary>
        /// Handles the Click event of the ChooseColorForEachClass control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ChooseColorForEachClass_Click(object sender, EventArgs e)
        {
            Choose_color newChoose = new Choose_color();
            newChoose.SetInfo(this.NumberOfClass);
            newChoose.ShowDialog();
            this.colorOfEachClass = newChoose.ForEach;
        }
        private int countSample = 0;
        /// <summary>
        /// Handles the MouseClick event of the picOriginalImage control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private void picOriginalImage_MouseClick(object sender, MouseEventArgs e)
        {
            List<int>[] c = new List<int>[8];
            countSample++;
            this.lbSamplenum.Text = countSample.ToString();
            this.classInfo[this.ClassIndexNow].data.Add(this.ValuesOfFeatures[e.X, e.Y]);
            if (this.MyType == TypeOfClassify.k_mean)
            {
                this.centers[countSample - 1] = this.ValuesOfFeatures[e.X, e.Y];
            }
        }

        

        /// <summary>
        /// Handles the Click event of the likelihoodToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void likelihoodToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClassIndexNow = 0;
            this.MyType = TypeOfClassify.Likelihood;
            this.GBResult.Visible = true;
        }

       

        private void parzenWindowToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            ClassIndexNow = 0;
            this.MyType = TypeOfClassify.parzenWindow;
            this.PazernWinGb.Visible = true;
            this.GBResult.Visible = true;
        }

        private void ClassSample_Click(object sender, EventArgs e)
        {
            if (this.MyType == TypeOfClassify.k_mean)
            {
                MessageBox.Show("You entered " + countSample.ToString() + " centers");
            }
            else
            {
                countSample = 0;
                MessageBox.Show("You entered class " + this.ClassIndexNow.ToString());
                this.ClassIndexNow++;
            }
        }

        private void knNearstNeighboorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClassIndexNow = 0;
            this.MyType = TypeOfClassify.KNearestNeighbour;
            this.GbKnear.Visible = true;
            this.GBResult.Visible = true;
        }


        private void kmeansToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClassIndexNow = 0;
            this.MyType = TypeOfClassify.k_mean;
            this.centers = new double[this.NumberOfClass];
            label6.Text = "please enter " + this.NumberOfClass.ToString() + "centers by clicking on the pic and then press Done";
        
        }       

    }
}
